package br.ufc.apsoo.repositories;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.Query;

import org.hibernate.Criteria;
import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;

import br.com.caelum.vraptor.ioc.Component;
import br.ufc.apsoo.models.Apartamento;
import br.ufc.apsoo.models.Hospede;
import br.ufc.apsoo.models.Reserva;
import br.ufc.apsoo.models.Situacao;

@Component
public class ReservaRepositoryImpl extends Repository<Reserva, Serializable>
		implements TodasReservas {

	private final Session session;

	protected ReservaRepositoryImpl(EntityManager entityManager) {
		super(entityManager);
		session = (Session) entityManager.getDelegate();
	}

	@Override
	public void cancelar(Reserva reserva) {
		// TODO Auto-generated method stub
	}

	@Override
	public void checkin(Reserva reserva) {
		reserva.checkin();
		this.update(reserva);
	}

	@Override
	public void checkout(Reserva reserva) {
		reserva.setDataSaida(new Date());
		reserva.checkout();
		this.update(reserva);
	}

	@Override
	public List<Reserva> naoLivres() {
		Criteria criteria = session.createCriteria(Reserva.class);
		criteria.add(Restrictions.ne("situacao", Situacao.LIVRE));
		criteria.addOrder(Order.desc("dataEntrada"));
		return criteria.list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Reserva> ocupadaPor(Hospede hospede) {
		StringBuilder hqlBuilder = new StringBuilder();

		hqlBuilder.append("select r ");
		hqlBuilder.append("from   br.ufc.apsoo.models.Reserva r ");
		hqlBuilder.append("where  r.situacao = :ocupado ");

		if (!hospede.getNome().isEmpty()) {
			hqlBuilder.append("and  lower(r.hospede.nome) like lower(:nome) ");
		}
		if (!hospede.getCpf().isEmpty()) {
			hqlBuilder.append("and  r.hospede.cpf = :cpf ");
		}

		Query query = entityManager.createQuery(hqlBuilder.toString())
				.setParameter("ocupado", Situacao.OCUPADO);

		if (!hospede.getNome().isEmpty()) {
			query.setParameter("nome", "%" + hospede.getNome() + "%");
		}
		if (!hospede.getCpf().isEmpty()) {
			query.setParameter("cpf", hospede.getCpf());
		}

		List<Reserva> reservas = query.getResultList();

		return reservas;
	}

	@Override
	public List<Reserva> ocupadaPor(String nomeHospede) {
		StringBuilder hqlBuilder = new StringBuilder();

		hqlBuilder.append("select r ");
		hqlBuilder.append("from   br.ufc.apsoo.models.Reserva r ");
		hqlBuilder.append("where  r.situacao = :ocupado ");
		hqlBuilder.append("and  lower(r.hospede.nome) like lower(:nome) ");

		Query query = entityManager.createQuery(hqlBuilder.toString())
				.setParameter("ocupado", Situacao.OCUPADO);

		query.setParameter("nome", "%" + nomeHospede + "%");

		List<Reserva> reservas = query.getResultList();

		return reservas;
	}

	@Override
	public Reserva ocupandoApartamento(Apartamento apartamento) {
		StringBuilder hqlBuilder = new StringBuilder();

		hqlBuilder.append("select r ");
		hqlBuilder.append("from   br.ufc.apsoo.models.Reserva r ");
		hqlBuilder.append("where  r.apartamento.numero = :numero ");
		hqlBuilder.append("and	  r.situacao = :ocupado ");

		Object o = entityManager.createQuery(hqlBuilder.toString())
				.setParameter("numero", apartamento.getNumero())
				.setParameter("ocupado", Situacao.OCUPADO).getSingleResult();
		return (Reserva) o;
	}

	@Override
	public List<Reserva> porSituacao(Situacao situacao) {

		Criteria criteria = session.createCriteria(Reserva.class);
		criteria.add(Restrictions.eq("situacao", situacao));
		criteria.addOrder(Order.desc("dataEntrada"));

		return criteria.list();
	}

	@Override
	public void realizar(Reserva reserva) {
		this.create(reserva);
	}

	@Override
	public Reserva trazerPorId(Long id) {
		return this.find(id);
	}

	@Override
	public BigDecimal queFaturaramEm(Integer mes) {
		Criteria criteria = session.createCriteria(Reserva.class);
		criteria.add(Restrictions.sqlRestriction(
				"extract(month from data_saida) = ?", mes, Hibernate.INTEGER));
		criteria.add(Restrictions.eq("situacao", Situacao.LIVRE));
		BigDecimal faturamento = BigDecimal.ZERO;

		List<Reserva> reservas = criteria.list();

		for (Reserva reserva : reservas) {
			faturamento = faturamento.add(reserva.getValorTotalDeDespesas()
					.add(reserva.getValorTotalDeDiarias()));
		}

		return faturamento;

	}
}
